/**
 * 
 * @brief  bsp.c
 * @param  None
 * 
 * @author xhq
 * @date   2024/11/05
 * 
 */
/* include */
#include "bsp.h"
#include "rc8088_load_config.h"
/* define */

/* typedef */

/* global varibles */

/* private function */

/* function */
/*****************************************************************************/
/**
*
* bsp_init
*
* @param	None.
*
* @return	返回结果，0：成功；其他：错误代码
*
* @note		None.
*
******************************************************************************/
uint32_t bsp_init(void)
{
    uint32_t l_u32_ret = 0;

    /* init gpio */   
    if (bsp_gpio_init() != 0)
    {
        SET_ERROR_CODE(l_u32_ret, 0);
        goto error;
    }
//    chip_en_8088();
  
    /* init spi */
    if (bsp_spi_init() != 0)
    {
        SET_ERROR_CODE(l_u32_ret, 1);
        goto error;
    }

    /* init RF_SKRL 斯凯瑞力射频芯片 */
    //
#ifdef FAR_RF_EN
    if(rf_skrl_init(0) != 0)
    {
        SET_ERROR_CODE(l_u32_ret, 2);
        goto error;
    }
#endif
#ifdef NEAR_RF_EN
    if(rf_skrl_init(2) != 0)
    {
        SET_ERROR_CODE(l_u32_ret, 2);
        goto error;
    }
#endif
    usleep(50000);

    /* init mipi */
    if (bsp_mipi_init() != 0)
    {
        SET_ERROR_CODE(l_u32_ret, 3);
        goto error;
    }
    /* 3.开启dma */
#ifdef FAR_RF_EN   
    if (bsp_mipi_start_dma(0) != 0)
    {
        printf("bsp_mipi0_start_dma err!\n");
    }

    if (bsp_mipi_start_dma(1) != 0)
    {
        printf("bsp_mipi1_start_dma err!\n");
    }
 #endif

 #ifdef NEAR_RF_EN 
    if (bsp_mipi_start_dma(2) != 0)
    {
        printf("bsp_mipi0_start_dma err!\n");
    }

    if (bsp_mipi_start_dma(3) != 0)
    {
        printf("bsp_mipi1_start_dma err!\n");
    }
#endif

    error:
    RETURN_ERROR_CODE(l_u32_ret, __func__);
}
/**
 * @brief create_semaphore 初始化信号量及互斥锁
 * 
 * @param None
 * 
 * @return uint32_t ：返回结果，0：正常，非0：错误代码
 * 
 * @note：
 */
uint32_t create_semaphore()
{
    uint32_t l_u32_ret = 0;
    uint32_t i = 0, j = 0;

    /* 初始化数据处理信号量 */
    if (sem_init(&g_data_pro_semaphore, 0, 0) != 0) 
    {
        SET_ERROR_CODE(l_u32_ret, 0);
    }
    /* 初始化dsp数据处理信号量 */
    if (sem_init(&g_dsp_pro_semaphore, 0, 0) != 0) 
    {
        SET_ERROR_CODE(l_u32_ret, 1);
    }
    /* 初始化mipi数据保存到ssd信号量 */
    if (sem_init(&g_mipi_add_ssd_semaphore, 0, 0) != 0) 
    {
        SET_ERROR_CODE(l_u32_ret, 2);
    }
    /* 初始化mipi数据发送至上位机信号量 */
    if (sem_init(&g_mipi_send_up_semaphore, 0, 0) != 0) 
    {
        SET_ERROR_CODE(l_u32_ret, 3);
    }
 
    /* mipi数据上传收到回复信号量初始化 */
    if (sem_init(&g_mipi_send_res_semaphore, 0, 0) != 0) 
    {
        SET_ERROR_CODE(l_u32_ret, 4);
    }

    if (sem_init(&g_dsp_pro_comlete_semaphore, 0, 0) != 0) 
    {
        SET_ERROR_CODE(l_u32_ret, 5);
    }

    if (sem_init(&g_track_process_semaphore, 0, 0) != 0) 
    {
        SET_ERROR_CODE(l_u32_ret, 6);
    }

    /* 初始化rf互斥锁 */
    if (pthread_mutex_init(&g_rf_semaphore, NULL) != 0) 
    {
        SET_ERROR_CODE(l_u32_ret, 7);
    }
    /* 初始化ini互斥锁 */
    if (pthread_mutex_init(&g_ini_semaphore, NULL) != 0) 
    {
        SET_ERROR_CODE(l_u32_ret, 8);
    }
    /* 初始化net param互斥锁 */
    if (pthread_mutex_init(&g_net_param_semaphore, NULL) != 0) 
    {
        SET_ERROR_CODE(l_u32_ret, 9);
    }
    /* 初始化net send互斥锁 */
    if (pthread_mutex_init(&g_net_send_semaphore, NULL) != 0) 
    {
        SET_ERROR_CODE(l_u32_ret, 10);
    }
    /* 初始化dsp参数配置互斥锁 */
    if (pthread_mutex_init(&g_dsp_param_semaphore, NULL) != 0) 
    {
        SET_ERROR_CODE(l_u32_ret, 11);
    }
    /* 初始化mipi数据保存到ssd队列互斥锁 */
    if (pthread_mutex_init(&g_Mutext_mipi_add_ssd, NULL) != 0) 
    {
        SET_ERROR_CODE(l_u32_ret, 12);
    }
    /* 初始化mipi数据发送至上位机队列互斥锁数组 */
    for (i = 0; i < MIPI_CHANNEL_MAX; i++)
    {
       
        if (pthread_mutex_init(&g_Mutext_mipi_send_up[i], NULL) != 0) 
        {
            SET_ERROR_CODE(l_u32_ret, 13);
        }

    }
    /* 初始化接收mipi数据计数值的互斥锁 */
    if (pthread_mutex_init(&g_Mutext_mipi_recv_cnt, NULL) != 0) 
    {
        SET_ERROR_CODE(l_u32_ret, 14);
    }

    error:
    RETURN_ERROR_CODE(l_u32_ret, __func__);
}

/***************************get ini param start**************************************/
/**
 * @brief Get the appsys config 获取应用配置
 * 
 * @param sys_config ：系统配置句柄
 * 
 * @return uint32_t ：返回结果，0：正常，非0：错误代码
 * 
 * @note：
 */
uint32_t get_appsys_config(sys_config_type * sys_config)
{
    uint32_t l_u32_ret = 0;
    int l_i32_error = 0;
    uint8_t rf_far_json_path[256] = {0};
    uint8_t rf_near_json_path[256] = {0};

    /* 获取应用配置 */
    /* 获取当前应用path */ 
    if (0 != (l_i32_error = get_app_file_absolute_path(APP_BIN_CONFIG_APPSYS_CONF_NAME, BIN_CONFIG, 
            sys_config->appsys.ini.filename, sizeof(sys_config->appsys.ini.filename))))
    {
        SET_ERROR_CODE(l_u32_ret, 0);
        goto error;
    }

    /* 获取当前应用及网络配置 */
    if (0 != (l_i32_error = inifile_config_parse(&sys_config->appsys, &sys_config->ini_info.section)))
    {
        SET_ERROR_CODE(l_u32_ret, 1);
        goto error;
    }

    /* 将获取的网络配置复制给网络全局变量 */
    if (0 != (l_i32_error = get_net_param_from_ini(&sys_config->ini_net_info)))
    {
        SET_ERROR_CODE(l_u32_ret, 2);
        goto error;
    }

    /* 设备全局变量赋值from ini */
    //rf 远端参数
    get_far_default_config();
    memcpy(rf_far_json_path, g_sys_info.app_path.file_path[BIN_CONFIG], sizeof(rf_far_json_path));
    strcat(rf_far_json_path, RF_FAR_USR_CONFIG_JSON_FILE);
    printf("far usr json path is %s.\n", rf_far_json_path);
    if (0 != (l_i32_error = rf_config_load(rf_far_json_path, (void*)&g_rf_far_userconfig)))
    {
        rf_config_save(RF_FAR_USR_CONFIG_JSON_FILE, (void*)&g_rf_far_userconfig_default);
        memcpy(&g_rf_far_userconfig,&g_rf_far_userconfig_default,sizeof(g_rf_far_userconfig_default));
    }
    printf("++++++++++++++far default:use+++++++++++++++++\n");
    check_data(&g_rf_far_userconfig_default,&g_rf_far_userconfig);

    //rf 近端参数
    get_near_default_config();
    memcpy(rf_near_json_path, g_sys_info.app_path.file_path[BIN_CONFIG], sizeof(rf_near_json_path));
    strcat(rf_near_json_path, RF_NEAR_USR_CONFIG_JSON_FILE);
    printf("near usr json path is %s.\n", rf_near_json_path);
    if (0 != (l_i32_error = rf_config_load(rf_near_json_path, (void*)&g_rf_near_userconfig)))
    {
        rf_config_save(RF_NEAR_USR_CONFIG_JSON_FILE, (void*)&g_rf_near_userconfig_default);
        memcpy(&g_rf_near_userconfig,&g_rf_near_userconfig_default,sizeof(g_rf_near_userconfig_default));
    }
    printf("++++++++++++++near default:use+++++++++++++++++\n");
    check_data(&g_rf_near_userconfig_default,&g_rf_near_userconfig);


 error:   
    RETURN_ERROR_CODE(l_u32_ret, __func__);
}


/**
 * @brief 基于程序的绝对路径计算可执行程序名称的长度
 * 
 * @param p_absolute_path ：程序的绝对路径
 * 
 * @return -1:失败；filename_len ：可执行程序名称的长度
 * 
 * @note：
 */
int32_t get_bin_name_len(char *p_absolute_path)
{
    if (p_absolute_path == NULL)
    {
        printf("get_bin_name_len param err.\n");
        return -1;
    }
    
    char *last_slash = NULL;
    char *filename = NULL;
    size_t filename_len = 0;

    last_slash = strrchr(p_absolute_path, '/');
    if (last_slash != NULL) 
    {
        filename = last_slash + 1;      // 文件名从斜杠后开始
    } 
    else 
    {
        filename = p_absolute_path;     // 没有斜杠，整个路径就是文件名
    }

    filename_len = strlen(filename);

    return filename_len;
}

/**
 * @brief Get the app absolute path 获取应用绝对地址
 * 
 * 
 * @return uint32_t ：返回结果，0：正常，非0：错误代码
 * 
 * @note：
 */
uint32_t get_app_absolute_path(void)
{
    uint32_t l_u32_ret = 0;
    ssize_t l_ssize_len = 0;
    ssize_t l_filename_len = 0;

    /* 应用目录路径初始化 */
    l_ssize_len = readlink("/proc/self/exe", g_sys_info.app_path.root_path, 200);
    if (-1 == l_ssize_len)
    {
        perror("[error -1][get_app_absolute_path]readlink fail!\n");
        SET_ERROR_CODE(l_u32_ret, 1);
    }
    else if(255 == l_ssize_len)
    {
    	perror("[error -2][get_app_absolute_path]path may be truncated!\n");
        SET_ERROR_CODE(l_u32_ret, 2);
    }
    else
    {
        /* 获取可执行文件名称长度 */
        l_filename_len = get_bin_name_len(g_sys_info.app_path.root_path);
        if (l_filename_len == -1)
        {
            perror("[error -3][get_bin_name_len] failed!\n");
            SET_ERROR_CODE(l_u32_ret, 3);
        }
        else
        {
            printf("bin name len is %d.\n", l_filename_len);
        }

        l_ssize_len = l_ssize_len - l_filename_len;
        g_sys_info.app_path.root_path[l_ssize_len] = '\0';
        
        sprintf(g_sys_info.app_path.file_path[BIN_CONFIG], "%sconfig/", g_sys_info.app_path.root_path);
        sprintf(g_sys_info.app_path.file_path[BIN_CONFIG_DEFAULT], "%sconfig_default/", g_sys_info.app_path.root_path);
        sprintf(g_sys_info.app_path.file_path[BIN_UPDATE], "%sconfig/update/", g_sys_info.app_path.root_path);

        if (access(g_sys_info.app_path.file_path[BIN_UPDATE], 0) == -1)
        {
            if (mkdir(g_sys_info.app_path.file_path[BIN_UPDATE], 0x777))
            {
                perror("[error -4][get_app_absolute_path] create \"update\" failed!\n");
                SET_ERROR_CODE(l_u32_ret, 4);
            }
        }
    }

    // config failed // 这里清空数组空间的方法有风险
    if (l_u32_ret != 0)
    {
        g_sys_info.app_path.root_path[0] = '\0';
        for (int l_i32_i = 0; l_i32_i < BIN_FILE_MAX; l_i32_i++)
        {
            g_sys_info.app_path.file_path[l_i32_i][0] = '\0';
        }
        g_sys_info.app_path.init_flag = 0;
    }
    else
    {
        g_sys_info.app_path.init_flag = 1;
    }

    error:
    RETURN_ERROR_CODE(l_u32_ret, __func__);
}
/**
 * @brief Get the app file absolute path 获取文件绝对路径
 * 
 * @param file_name ：文件名
 * @param file_type ：文件夹名
 * @param path ：缓存路径
 * @param limit_len ：路径字符串长度限制
 * 
 * @return uint32_t ：0：正常，非0：错误代码
 * 
 * @note：
 */
uint32_t get_app_file_absolute_path(const char * file_name, const uint32_t file_type, char * path, const ssize_t limit_len)
{
    uint32_t l_u32_ret = 0;
    ssize_t l_sszie_len = 0;

    /* 检查参数合法性 */
    if (1 != g_sys_info.app_path.init_flag)
    {
        if (0 != get_app_absolute_path())
        {
            SET_ERROR_CODE(l_u32_ret, 0);
            perror("[error -1][get_app_config_absolute_path]get_app_absolute_path fail!\n");
        }
    }

    if (BIN_FILE_MAX <= file_type)
    {
        SET_ERROR_CODE(l_u32_ret, 1);
        perror("[error -1][get_app_config_absolute_path]file_type invalid!\n");
    }
    else
    {
        l_sszie_len = strlen(g_sys_info.app_path.file_path[file_type]);
        if (limit_len <= (l_sszie_len + strlen(file_name)))
        {
            SET_ERROR_CODE(l_u32_ret, 2);
            perror("[error -2][get_app_config_absolute_path]limit_len <= sizeof(path)!\n");
        }
    }
    
    /* return file_path */
    if (0 == l_u32_ret)
    {
        strcpy(path, g_sys_info.app_path.file_path[file_type]);
        strcat(path, file_name);
    }
    else
    {
        path[0] = '\0';
    }

    error:
    RETURN_ERROR_CODE(l_u32_ret, __func__);
}
/**
 * @brief 初始化系统配置变量
 * 
 * @param sys_config ：系统配置句柄
 * 
 * @return uint32_t ：
 * 
 * @note：
 */
uint32_t sys_config_init(sys_config_type * sys_config)
{
    uint32_t l_u32_ret = 0;

    memset(sys_config, 0, sizeof(sys_config_type));

    // ini_config
    do
    {
        strcpy((char *)sys_config->appsys.ini.filename, APP_BIN_CONFIG_APPSYS_CONF_NAME);
        sys_config->appsys.ini.section_num = SECTION_MAX;
        strcpy((char *)sys_config->appsys_backup.ini.filename, APP_BIN_CONFIG_APPSYS_BACKUP_CONF_NAME);
        sys_config->appsys_backup.ini.section_num = SECTION_MAX;
        strcpy((char *)sys_config->appsys_default.ini.filename, APP_BIN_CONFIG_APPSYS_DEFAULT_CONF_NAME);
        sys_config->appsys_default.ini.section_num = SECTION_MAX;
    } while (0);
    // ini_info
    do
    {
        strcpy(sys_config->ini_info.section.base.name, "ini_info");
        sys_config->ini_info.section.base.member_num = MEMBER_NUM_OF_SECTION(ini_info_type);
        strcpy(sys_config->ini_info.project_name.name, "project_name");
        sys_config->ini_info.project_name.type = TYPE_STRING;
        strcpy(sys_config->ini_info.sw_version.name, "sw_version");
        sys_config->ini_info.sw_version.type = TYPE_STRING;
        strcpy(sys_config->ini_info.compile_time.name, "compile_time");
        sys_config->ini_info.compile_time.type = TYPE_STRING;
    } while (0);

    // net_info
    do
    {
        strcpy(sys_config->ini_net_info.section.base.name, "ini_net_info");
        sys_config->ini_net_info.section.base.member_num = MEMBER_NUM_OF_SECTION(ini_net_info_type);
        
        // ipv4
        strcpy(sys_config->ini_net_info.ip4_local_ip.name, "ip4_local_ip");
        sys_config->ini_net_info.ip4_local_ip.type = TYPE_STRING;
        strcpy(sys_config->ini_net_info.ip4_dest_ip.name, "ip4_dest_ip");
        sys_config->ini_net_info.ip4_dest_ip.type = TYPE_STRING;
        strcpy(sys_config->ini_net_info.ip4_mask.name, "ip4_mask");
        sys_config->ini_net_info.ip4_mask.type = TYPE_STRING;
        strcpy(sys_config->ini_net_info.ip4_gateway.name, "ip4_gateway");
        sys_config->ini_net_info.ip4_gateway.type = TYPE_STRING;
        
        // ipv6
        strcpy(sys_config->ini_net_info.ip_ipv6.name, "ip_ipv6");
        sys_config->ini_net_info.ip_ipv6.type = TYPE_STRING;
        strcpy(sys_config->ini_net_info.ip_local_ipv6.name, "ip_local_ipv6");
        sys_config->ini_net_info.ip_local_ipv6.type = TYPE_STRING;
        strcpy(sys_config->ini_net_info.ip_global_ipv6.name, "ip_global_ipv6");
        sys_config->ini_net_info.ip_global_ipv6.type = TYPE_STRING;
        strcpy(sys_config->ini_net_info.mask_ipv6.name, "mask_ipv6");
        sys_config->ini_net_info.mask_ipv6.type = TYPE_STRING;
        strcpy(sys_config->ini_net_info.gateway_ipv6.name, "gateway_ipv6");
        sys_config->ini_net_info.gateway_ipv6.type = TYPE_STRING;

        // cmd/data port
        strcpy(sys_config->ini_net_info.data_local_port.name, "data_local_port");
        sys_config->ini_net_info.data_local_port.type = TYPE_INT;
        strcpy(sys_config->ini_net_info.data_dest_port.name, "data_dest_port");
        sys_config->ini_net_info.data_dest_port.type = TYPE_INT;
        strcpy(sys_config->ini_net_info.cmd_local_port.name, "cmd_local_port");
        sys_config->ini_net_info.cmd_local_port.type = TYPE_INT;
        strcpy(sys_config->ini_net_info.cmd_dest_port.name, "cmd_dest_port");
        sys_config->ini_net_info.cmd_dest_port.type = TYPE_INT;
        strcpy(sys_config->ini_net_info.mac.name, "mac");
        sys_config->ini_net_info.mac.type = TYPE_STRING;

        // protocol 0:ipv4, 1:ipv6
        strcpy(sys_config->ini_net_info.data_protocol.name, "data_protocol");
        sys_config->ini_net_info.data_protocol.type = TYPE_INT;
        strcpy(sys_config->ini_net_info.cmd_protocol.name, "cmd_protocol");
        sys_config->ini_net_info.cmd_protocol.type = TYPE_INT;
    } while (0);

    // local_net_info

    // lidar

    error:
    RETURN_ERROR_CODE(l_u32_ret, __func__);
}
/***************************get ini param end**************************************/
/**
 * @brief 存储采集的原始数据
 * 
 * @param buf ：待存储的数组指针
 * @param len ：待存储的数组大小，字节byte
 * 
 * @return uint32_t ：
 * 
 * @note：
 */
 uint32_t save_data_to_ssd(uint8_t *buf, uint32_t len, uint32_t flag, uint32_t fram_count)
 {
     int fd;
     FILE *fp = NULL;
     // char time_name[100] = {0};
     char dir_name[64] = {0};
     char filename[64] = {0};
     uint32_t l_u32_ret = 0;
     // time_t l_current_time;
     // struct tm *l_time_info;
 
     // struct timespec l_timespec_start = {0};
     // struct timespec l_timespec_end = {0};
     // uint32_t l_running_time_us = 0;
 
     /* 获取对应的mipi通道号和接收线程序号 */
     uint16_t l_u16_mipi_channel_i  = (uint16_t)((flag & 0xffff0000) >> 16);     // mipi通道号 0, 1
     uint16_t l_u16_mipi_recv_num_j = (uint16_t)(flag & 0x0000ffff);             // mipi接收线程数 0～3
 
     /* 获取当前时间 */
     // time(&l_current_time);
     // l_time_info = localtime(&l_current_time);       // 将时间转换为本地时间
     // strftime(time_name, sizeof(time_name), "%Y_%m_%d_%H_%M_%S", l_time_info);
     // sprintf(dir_name, "/home/lds/mipi_data/%s/mipi%d", time_name, l_u16_mipi_channel_i);
     // sprintf(dir_name, "/home/lds/mipi_data/mipi%d", l_u16_mipi_channel_i);
     sprintf(dir_name, "/run/media/sda1/mipi_data/count_%d_pthreadnum_%d_mipichannel_%d", fram_count, l_u16_mipi_recv_num_j, l_u16_mipi_channel_i);
     sprintf(filename, "%s_data.bin", dir_name);
     // sprintf(filename, "/run/media/sda1/mipi_data/mipi%d_%d_fram_data_%d.bin", l_u16_mipi_channel_i, l_u16_mipi_recv_num_j, fram_count);
     // printf("filename:%s\n", filename);
 
     // 判断目录是否存在
     // struct stat st;
     // if (stat(dir_name, &st) != 0)
     // {
     //     mkdir(dir_name, 0666);
     // }
     // else
     // {
     //     // mkdir(dir_name, 0666);
     // }
 
     /* 创建文件 */
     fp = fopen(filename, "w");
     if (fp == NULL)
     {
         printf("save_data_to_ssd fopen failed.\n");
         SET_ERROR_CODE(l_u32_ret, 0);
         goto error;
     }
 
     /* 保存数据开始计时 */
     // clock_gettime(CLOCK_MONOTONIC_RAW, &l_timespec_start);
 
     /* 写入数据 */
     fwrite(buf, 1, len, fp);
     // fwrite(g_temp_mipi, 1, len, fp);
 
     /* 同步进内存 */
     // sync();
 
     // /* 保存数据结束，统计操作耗时 */
     // clock_gettime(CLOCK_MONOTONIC_RAW, &l_timespec_end);
     // l_running_time_us = (l_timespec_end.tv_sec - l_timespec_start.tv_sec) * 1000000 + 
     //                         (l_timespec_end.tv_nsec - l_timespec_start.tv_nsec) / 1000;
     // printf("%d %d %d %uus %ums\n", l_u16_mipi_channel_i,l_u16_mipi_recv_num_j,fram_count,l_running_time_us,l_running_time_us/1000);
 
     error:
     /* 关闭文件 */
     if (fp != NULL)
     {
         fclose(fp);
     }
     RETURN_ERROR_CODE(l_u32_ret, __func__);
 }
